package ace.tool.generate.code.impl.resolver.scheme.resolver.api;

import ace.cmp.util.CaseFormatUtils;
import ace.tool.generate.code.impl.manager.common.EntityModelManager;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.api.DtoClassFieldInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.api.DtoClassFieldRemarkMetaInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.api.DtoClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.api.EnumClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.ClassFileInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.CommonInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.dto.ProjectInfo;
import ace.tool.generate.code.impl.resolver.scheme.resolver.ClassFileInfoResolver;
import ace.tool.generate.code.impl.service.model.input.GenerateInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelFieldInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelInput;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author caspar
 * @date 2023/11/17 10:34
 */
public class DtoClassInfoResolver {

  private static final String REMARK_META_COLUMN_NAME = "_COLUMN_NAME";
  private static final String REMARK_META_TITLE = "_TITLE";
  private static final String REMARK_META_DESC = "_DESC";
  private final GenerateInput input;
  private final GenerateModelInput modelInput;
  private final CommonInfo commonInfo;
  private final ProjectInfo apiProjectInfo;
  private final List<EnumClassInfo> enumClassInfos;
  private final EntityModelManager entityModelManager = new EntityModelManager();

  public DtoClassInfoResolver(
      GenerateInput input,
      GenerateModelInput modelInput,
      CommonInfo commonInfo,
      ProjectInfo apiProjectInfo,
      List<EnumClassInfo> enumClassInfos) {
    this.input = input;
    this.modelInput = modelInput;
    this.commonInfo = commonInfo;
    this.apiProjectInfo = apiProjectInfo;
    this.enumClassInfos = enumClassInfos;
  }

  public DtoClassInfo resolve() {
    String entityModelId = new EntityModelManager().getEntityModelId(input, modelInput);

    ClassFileInfo dtoClassFileInfo =
        new ClassFileInfoResolver(
            apiProjectInfo.getSourceCodeRootDir(),
            this.modelInput.getName(),
            input.getDtoClassNameSuffix(),
            input.getDtoClassPackagePrefix(),
            commonInfo.getRootPackageFullName())
            .resolve();
    String tableName = this.entityModelManager.convertClassNameToTableName(this.modelInput.getName());
    return DtoClassInfo.builder()
        .entityModelId(entityModelId)
        .tableName(tableName)
        .info(dtoClassFileInfo)
        .fieldInfos(this.getFieldInfos())
        .outputDtoRemarkFlag(this.modelInput.getOutputDtoRemarkFlag())
        .build();
  }

  private List<DtoClassFieldInfo> getFieldInfos() {
    List<DtoClassFieldInfo> fields =
        modelInput.getFields().stream().map(this::getFieldInfo).collect(Collectors.toList());

    if (this.isNeedAddDeleteFlag(fields)) {
      fields.add(this.getDefaultDeleteField());
    }
    if (input.getEnableCreateTimeField()) {
      fields.add(this.getDefaultCreateTimeField());
    }
    if (input.getEnableUpdateTimeField()) {
      fields.add(this.getDefaultUpdateTimeField());
    }
    if (input.getEnableRowVersionField()) {
      fields.add(this.getDefaultRowVersionField());
    }

    fields.forEach(this::getFieldRemarkMeta);
    return fields;
  }

  private void getFieldRemarkMeta(DtoClassFieldInfo dtoClassFieldInfo) {
    String baseFieldName = CaseFormatUtils.convertLowerCamelToUpperUnderscore(dtoClassFieldInfo.getName());
    String columnName = this.entityModelManager.convertFieldNameToColumnName(dtoClassFieldInfo.getName());

    DtoClassFieldRemarkMetaInfo remarkMetaInfo = DtoClassFieldRemarkMetaInfo.builder()
        .columnNameFieldName(baseFieldName + REMARK_META_COLUMN_NAME)
        .columnName(columnName)

        .titleFieldName(CaseFormatUtils.convertLowerCamelToUpperUnderscore(dtoClassFieldInfo.getName()) + REMARK_META_TITLE)
        .titleFieldContent(dtoClassFieldInfo.getRemark())

        .descFieldName(CaseFormatUtils.convertLowerCamelToUpperUnderscore(dtoClassFieldInfo.getName()) + REMARK_META_DESC)
        .descFieldContent(dtoClassFieldInfo.getRemarkNotes())
        .build();

    dtoClassFieldInfo.setRemarkMeta(remarkMetaInfo);
  }

  private boolean isNeedAddDeleteFlag(List<DtoClassFieldInfo> fields) {
    boolean isExitsDeleteFlagField =
        fields.stream().anyMatch(p -> p.getName().equals(input.getDeleteFlagFieldName()));
    return input.getEnableDeleteFlagField() && !isExitsDeleteFlagField;
  }

  private DtoClassFieldInfo getDefaultRowVersionField() {
    return DtoClassFieldInfo.builder()
        .name(input.getRowVersionFieldName())
        .remark("版本号和乐观锁")
        .remarkNotes("")
        .type(Long.class.getSimpleName())
        .nullable(false)
        .build();
  }

  private DtoClassFieldInfo getDefaultUpdateTimeField() {
    return DtoClassFieldInfo.builder()
        .name(input.getUpdateTimeFieldName())
        .remark("更新时间")
        .remarkNotes("单位-毫秒")
        .type(Long.class.getSimpleName())
        .nullable(false)
        .build();
  }

  private DtoClassFieldInfo getDefaultCreateTimeField() {
    return DtoClassFieldInfo.builder()
        .name(input.getCreateTimeFieldName())
        .remark("创建时间")
        .remarkNotes("单位-毫秒")
        .type(Long.class.getSimpleName())
        .nullable(false)
        .build();
  }

  private DtoClassFieldInfo getDefaultDeleteField() {
    return DtoClassFieldInfo.builder()
        .name(input.getDeleteFlagFieldName())
        .remark("删除标识")
        .remarkNotes("0-未删除")
        .type(Long.class.getSimpleName())
        .nullable(false)
        .build();
  }

  private DtoClassFieldInfo getFieldInfo(GenerateModelFieldInput modelFieldInput) {
    Optional<EnumClassInfo> enumClassInfoOptional =
        this.entityModelManager.getEnumClassInfoBy(modelInput, modelFieldInput, enumClassInfos);
    String javaComment =
        this.entityModelManager.getModelFieldJavaComment(modelFieldInput, enumClassInfoOptional);
    return DtoClassFieldInfo.builder()
        .name(modelFieldInput.getName())
        .remark(modelFieldInput.getRemark())
        .remarkNotes(this.entityModelManager.getModelFieldEnumRemarkNotes(modelFieldInput))
        .javaComment(javaComment)
        .type(modelFieldInput.getType().getSimpleName())
        .nullable(modelFieldInput.getNullable())
        .stringSizeValid(this.entityModelManager.getStringSizeValid(modelFieldInput))
        .build();
  }
}
